package org.zergle.utils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 提供对JavaBean操作的一系列方法
 * 
 * @author Johnson.Lee
 */
public class Beans {

	/**
	 * not visible
	 */
	private Beans() {
	}

	/**
	 * 返回<code>JavaBean</code>的所有属性名称
	 * 
	 * @param clazz
	 *            JavaBean的Class实例
	 * @return 返回该Bean的所有属性名称
	 */
	public static String[] getPropertyNames(Class<?> clazz) {
		String[] properties = null;
		PropertyDescriptor[] pds = getPropertyDescriptors(clazz);
		properties = new String[pds.length];
		for (int i = 0; i < pds.length; i++) {
			properties[i] = pds[i].getName();
		}
		return properties;
	}

	/**
	 * 返回<code>JavaBean</code>指定属性名称的get方法
	 * 
	 * @param clazz
	 *            JavaBean的Class实例
	 * @param propertyName
	 *            属性名称
	 * @return 返回Bean的指定属性名称的get方法
	 */
	public static Method getter(Class<?> clazz, String propertyName) {
		PropertyDescriptor[] pds = getPropertyDescriptors(clazz);
		for (int i = 0; i < pds.length; i++) {
			if (pds[i].getName().equals(propertyName)) {
				return pds[i].getReadMethod();
			}
		}
		return null;
	}

	/**
	 * 返回<code>JavaBean</code>指定属性名称的set方法
	 * 
	 * @param clazz
	 *            JavaBean的Class实例
	 * @param propertyName
	 *            属性名称
	 * @return 返回Bean的指定属性名称的set方法
	 */
	public static Method setter(Class<?> clazz, String propertyName) {
		PropertyDescriptor[] pds = getPropertyDescriptors(clazz);
		for (int i = 0; i < pds.length; i++) {
			if (pds[i].getName().equals(propertyName)) {
				return pds[i].getWriteMethod();
			}
		}
		return null;
	}

	/**
	 * 返回<code>JavaBean</code>的所有属性描述器
	 * 
	 * @param clazz
	 *            JavaBean的Class实例
	 * @return 返回该Bean的所有属性描述器
	 */
	public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) {
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
			return beanInfo.getPropertyDescriptors();
		} catch (IntrospectionException e) {
		}
		return null;
	}

	/**
	 * 克隆对象。
	 * <p>
	 * 被克隆的对象必须实现<code>java.io.Serializable</code>接口
	 * </p>
	 * 
	 * @param object
	 *            待克隆对象
	 * @return 返回克隆的对象
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public static Object clone(Object object) throws IOException,
			ClassNotFoundException {
		if (object instanceof Serializable) {
			ByteArrayOutputStream baos = null;
			ByteArrayInputStream bais = null;
			ObjectOutputStream oos = null;
			ObjectInputStream ois = null;
			try {
				baos = new ByteArrayOutputStream();
				oos = new ObjectOutputStream(baos);
				oos.writeObject(object);
				oos.flush();
				baos.flush();
				bais = new ByteArrayInputStream(baos.toByteArray());
				ois = new ObjectInputStream(bais);
				return ois.readObject();
			} finally {
				try {
					if (oos != null) {
						oos.close();
						oos = null;
					}
					if (baos != null) {
						baos.close();
						baos = null;
					}
					if (ois != null) {
						ois.close();
						ois = null;
					}
					if (bais != null) {
						bais.close();
						bais = null;
					}
				} catch (IOException e) {
				}
			}

		}
		throw new NotSerializableException();
	}

	/**
	 * 返回对象指定名称的属性值
	 * 
	 * @param object
	 *            目标对象
	 * @param propertyName
	 *            属性名称
	 * @return 对象指定名称的属性值
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 *             当指定名称属性不存在时，抛出此异常
	 */
	public static Object getProperty(Object object, String propertyName)
			throws IllegalAccessException, InvocationTargetException {
		Method getter = getter(object.getClass(), propertyName);
		if (getter != null) {
			return getter.invoke(object);
		}
		return null;
	}

	/**
	 * 设置对象指定名称的属性值
	 * 
	 * @param object
	 * @param propertyName
	 *            属性名称
	 * @param value
	 *            属性值
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws InvocationTargetException
	 */
	public static void setProperty(Object object, String propertyName,
			Object value) throws IllegalAccessException,
			InvocationTargetException {
		Method setter = setter(object.getClass(), propertyName);
		if (setter != null) {
			setter.invoke(object, value);
		}
	}

}
